/**
 * Copyright &copy; 2013-2015 山东易科德软件有限公司 All rights reserved.
 */
package cn.net.ecode.modules.gen.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import cn.net.ecode.common.config.Global;
import cn.net.ecode.common.mapper.JaxbMapper;
import cn.net.ecode.common.utils.DateUtils;
import cn.net.ecode.common.utils.FileUtils;
import cn.net.ecode.common.utils.FreeMarkers;
import cn.net.ecode.common.utils.StringUtils;
import cn.net.ecode.modules.gen.entity.GenConfig;
import cn.net.ecode.modules.gen.entity.GenTable;
import cn.net.ecode.modules.gen.entity.GenTableColumn;
import cn.net.ecode.modules.gen.entity.GenTemplate;
import cn.net.ecode.modules.gen.entity.GenTplCategory;
import cn.net.ecode.modules.sys.entity.Area;
import cn.net.ecode.modules.sys.entity.Office;
import cn.net.ecode.modules.sys.entity.User;
import cn.net.ecode.modules.sys.utils.UserUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 代码生成工具类
 * @author ThinkGem
 * @version 2013-11-16
 */
public class GenUtils {

	private static Logger logger = LoggerFactory.getLogger(GenUtils.class);

	/**
	 * 初始化列属性字段
	 * @param genTable
	 */
	public static void initColumnField(GenTable genTable){
		for (GenTableColumn column : genTable.getColumnList()){
			
			// 如果是不是新增列，则跳过。
			if (StringUtils.isNotBlank(column.getId())){
				continue;
			}
			
			// 设置字段说明
			if (StringUtils.isBlank(column.getComments())){
				column.setComments(column.getColumnName());
			}
			
			// 根据字段类型，设置java类型
			if (StringUtils.startsWithIgnoreCase(column.getColumnType(), "date")
					|| StringUtils.startsWithIgnoreCase(column.getColumnType(), "timestamp")){
				column.setJavaType(Date.class.getName());
				column.setShowType("dateselect");
			}
			// 浮点数
			else if (StringUtils.startsWithIgnoreCase(column.getColumnType(), "float")
					|| StringUtils.startsWithIgnoreCase(column.getColumnType(), "double")){
				column.setJavaType(Double.class.getSimpleName());
			}
			// 整型
			else if (StringUtils.containsIgnoreCase(column.getColumnType(), "int")
					|| StringUtils.startsWithIgnoreCase(column.getColumnType(), "number")
					|| StringUtils.startsWithIgnoreCase(column.getColumnType(), "decimal")
					|| StringUtils.startsWithIgnoreCase(column.getColumnType(), "numeric")){
				// 如果是浮点型
				String[] ss = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
				if (ss != null && ss.length == 2 && Integer.parseInt(ss[1])>0){
					column.setJavaType(Double.class.getSimpleName());
				}
				// 如果是整型
				else if (ss != null && ss.length >= 1 && Integer.parseInt(ss[0])<=10){
					column.setJavaType(Integer.class.getSimpleName());
				}
				// 长整型
				else{
					column.setJavaType(Long.class.getSimpleName());
				}
			}
			// 字符串
			else{
				column.setJavaType(String.class.getSimpleName());
			}
			
			// 设置java字段名，驼峰命名法转换。
			column.setJavaField(StringUtils.toCamelCase(column.getColumnName()));
			
			// 是否是主键检测及设置。
			for (GenTableColumn pk : genTable.getPkList()){
				if (column.getColumnName().equals(pk.getColumnName())){
					column.setIsPk(Global.YES);
					column.setIsEdit(Global.YES);
					column.setShowType("hidden"); // 默认隐藏主键
				}
			}

			// 设置是否是插入字段
			column.setIsInsert(Global.YES);

			// 设置默认更新字段
			if (!Global.YES.equals(column.getIsPk())
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "create_by")	// 创建人字段
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "create_date") // 创建时间字段
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "status")		// 状态字段
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "corp_code")	// 集团编码
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "corp_name")	// 集团名称
					){
				column.setIsUpdate(Global.YES); // 更新语句中存在
				
				// 设置默认编辑字段
				if (!StringUtils.equalsIgnoreCase(column.getColumnName(), "update_by") 		// 更新人字段
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "update_date") // 更新时间字段
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "hasnext") 	// 树列表是否有下级
					&& !StringUtils.equalsIgnoreCase(column.getColumnName(), "sort_grade") 	// 树列表层次级别
					){
					column.setIsEdit(Global.YES); // 编辑表单中存在
				}
			}

			// 设置默认列表字段
			if (StringUtils.equalsIgnoreCase(column.getColumnName(), "name")
					|| StringUtils.equalsIgnoreCase(column.getColumnName(), "title")
					|| StringUtils.equalsIgnoreCase(column.getColumnName(), "remarks")
					|| StringUtils.equalsIgnoreCase(column.getColumnName(), "update_date")){
				column.setIsList(Global.YES);
			}
			
			// 设置默认查询字段
			if (StringUtils.equalsIgnoreCase(column.getColumnName(), "name")
					|| StringUtils.equalsIgnoreCase(column.getColumnName(), "title")){
				column.setIsQuery(Global.YES);
			}
			
			// 设置默认查询字段类型为双模糊查询
			if (StringUtils.equalsIgnoreCase(column.getColumnName(), "name")
					|| StringUtils.equalsIgnoreCase(column.getColumnName(), "title")){
				column.setQueryType("all_like");
			}

			// 设置特定类型和字段名
			
			// 用户
			if (StringUtils.startsWithIgnoreCase(column.getColumnName(), "user_code")){
				column.setJavaType(User.class.getName());
				column.setJavaField(column.getJavaField().replaceAll("Code", ".userCode|userName"));
				column.setShowType("userselect");
			}
			// 部门
			else if (StringUtils.startsWithIgnoreCase(column.getColumnName(), "office_code")){
				column.setJavaType(Office.class.getName());
				column.setJavaField(column.getJavaField().replaceAll("Code", ".officeCode|officeName"));
				column.setShowType("officeselect");
			}
			// 区域
			else if (StringUtils.startsWithIgnoreCase(column.getColumnName(), "area_code")){
				column.setJavaType(Area.class.getName());
				column.setJavaField(column.getJavaField().replaceAll("Code", ".areaCode|areaName"));
				column.setShowType("areaselect");
			}
			// 创建者、更新者
			else if (StringUtils.startsWithIgnoreCase(column.getColumnName(), "create_by")
					|| StringUtils.startsWithIgnoreCase(column.getColumnName(), "update_by")){
				column.setJavaType(User.class.getName());
				column.setJavaField(column.getJavaField() + ".userCode");
			}
			// 创建时间、更新时间
			else if (StringUtils.startsWithIgnoreCase(column.getColumnName(), "create_date")
					|| StringUtils.startsWithIgnoreCase(column.getColumnName(), "update_date")){
				column.setShowType("dateselect");
			}
			// 备注、内容
			else if (StringUtils.equalsIgnoreCase(column.getColumnName(), "remarks")
					|| StringUtils.equalsIgnoreCase(column.getColumnName(), "content")){
				column.setShowType("textarea");
			}
			// 父级ID
			else if (StringUtils.equalsIgnoreCase(column.getColumnName(), "parent_code")){
				column.setJavaType("This");
				column.setJavaField("parent.id|name");
				column.setShowType("treeselect");
			}
			// 所有父级ID
			else if (StringUtils.equalsIgnoreCase(column.getColumnName(), "parent_codes")){
				column.setQueryType("like");
			}
			// 树列表排序
			else if (StringUtils.equalsIgnoreCase(column.getColumnName(), "sorts")){
				column.setJavaType("Integer");
			}
			// 删除标记
			else if (StringUtils.equalsIgnoreCase(column.getColumnName(), "status")){
				//column.setIsQuery(Global.YES);
				column.setShowType("select");
				column.setDictType("search_status");
			}
		}
	}
	
//	/**
//	 * 获取模板路径
//	 * @return
//	 */
//	public static String getTemplatePath(){
//		String path = StringUtils.getProjectPath() + StringUtils.replaceEach(".src.main.java." + GenUtils.class.getName(), 
//				new String[]{"util."+GenUtils.class.getSimpleName(), "."}, new String[]{"template", File.separator});
////		logger.debug("template path: {}", path);
//		return path;
//	}
	
	/**
	 * XML文件转换为对象
	 * @param fileName
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fileToObject(String fileName, Class<?> clazz){
		try {
			String pathName = "/templates/modules/gen/" + fileName;
//			logger.debug("File to object: {}", pathName);
			Resource resource = new ClassPathResource(pathName); 
			InputStream is = resource.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			StringBuilder sb = new StringBuilder();  
			while (true) {
				String line = br.readLine();
				if (line == null){
					break;
				}
				sb.append(line).append("\r\n");
			}
			if (is != null) {
				is.close();
			}
			if (br != null) {
				br.close();
			}
//			logger.debug("Read file content: {}", sb.toString());
			return (T) JaxbMapper.fromXml(sb.toString(), clazz);
		} catch (IOException e) {
			logger.warn("Error file convert: {}", e.getMessage());
		}
//		String pathName = StringUtils.replace(getTemplatePath() + "/" + fileName, "/", File.separator);
//		logger.debug("file to object: {}", pathName);
//		String content = "";
//		try {
//			content = FileUtils.readFileToString(new File(pathName), "utf-8");
////			logger.debug("read config content: {}", content);
//			return (T) JaxbMapper.fromXml(content, clazz);
//		} catch (IOException e) {
//			logger.warn("error convert: {}", e.getMessage());
//		}
		return null;
	}
	
	/**
	 * 获取代码生成配置对象
	 * @return
	 */
	public static GenConfig getConfig(){
		return fileToObject("config.xml", GenConfig.class);
	}

	/**
	 * 根据分类获取模板列表
	 * @param config
	 * @param genScheme
	 * @param isChildTable 是否是子表
	 * @return
	 */
	public static List<GenTemplate> getTemplateList(GenConfig config, String category, boolean isChildTable){
		List<GenTemplate> templateList = Lists.newArrayList();
		if (config !=null && config.getTplCategoryList() != null && category !=  null){
			for (GenTplCategory e : config.getTplCategoryList()){
				if (category.equals(e.getValue())){
					List<String> list = null;
					if (!isChildTable){
						list = e.getTemplate();
					}else{
						list = e.getChildTableTemplate();
					}
					if (list != null){
						for (String s : list){
							if (StringUtils.startsWith(s, GenTplCategory.CATEGORY_REF)){
								templateList.addAll(getTemplateList(config, StringUtils.replace(s, GenTplCategory.CATEGORY_REF, ""), false));
							}else{
								GenTemplate template = fileToObject(s, GenTemplate.class);
								if (template != null){
									templateList.add(template);
								}
							}
						}
					}
					break;
				}
			}
		}
		return templateList;
	}
	
	/**
	 * 获取数据模型
	 * @param genTable
	 * @return
	 */
	public static Map<String, Object> getDataModel(GenTable genTable){
		Map<String, Object> model = Maps.newHashMap();
		
		model.put("packageName", StringUtils.lowerCase(genTable.getPackageName()));
		model.put("lastPackageName", StringUtils.substringAfterLast((String)model.get("packageName"),"."));
		model.put("moduleName", StringUtils.lowerCase(genTable.getModuleName()));
		model.put("subModuleName", StringUtils.lowerCase(genTable.getSubModuleName()));
		model.put("className", StringUtils.uncapitalize(genTable.getClassName()));
		model.put("ClassName", StringUtils.capitalize(genTable.getClassName()));
		
		model.put("functionName", genTable.getFunctionName());
		model.put("functionNameSimple", genTable.getFunctionNameSimple());
		model.put("functionAuthor", StringUtils.isNotBlank(genTable.getFunctionAuthor())?genTable.getFunctionAuthor():UserUtils.getUser().getUserName());
		model.put("functionVersion", DateUtils.getDate());
		
		model.put("urlPrefix", StringUtils.replace(model.get("moduleName")+(StringUtils.isNotBlank(genTable.getSubModuleName())
				?"/"+StringUtils.lowerCase(genTable.getSubModuleName()):"")+"/"+model.get("className"), ".", "/"));
		model.put("viewPrefix", //StringUtils.substringAfterLast(model.get("packageName"),".")+"/"+
				model.get("urlPrefix"));
		model.put("permissionPrefix", StringUtils.replace(model.get("moduleName")+(StringUtils.isNotBlank(genTable.getSubModuleName())
				?":"+StringUtils.lowerCase(genTable.getSubModuleName()):"")+":"+model.get("className"), ".", ":"));
		
		model.put("dbName", Global.getDbName());

		model.put("table", genTable);
		
		String pkField = StringUtils.EMPTY;
		if (genTable != null && genTable.getPkList() != null && genTable.getPkList().size() == 1) {
			pkField = genTable.getPkList().get(0).getSimpleJavaField();
		}
		model.put("pkField", pkField);
		
		return model;
	}
	
	/**
	 * 生成到文件
	 * @param tpl
	 * @param model
	 * @param genTable
	 * @return
	 */
	public static String generateToFile(GenTemplate tpl, Map<String, Object> model, GenTable genTable){
		
		// 设置生成基础路径
		if (StringUtils.isBlank(genTable.getGenBaseDir())){
			genTable.setGenBaseDir(Global.getProjectPath());
		}
		
		// 获取生成全文件名
		String fileName = genTable.getGenBaseDir() + File.separator 
				+ StringUtils.replaceEach(FreeMarkers.renderString(tpl.getFilePath() + "/", model), 
						new String[]{"//", "/", "."}, new String[]{File.separator, File.separator, File.separator})
				+ FreeMarkers.renderString(tpl.getFileName(), model);
		logger.debug("Generate File ==> \r\n" + fileName);

		// 获取生成文件内容
		String content = FreeMarkers.renderString(StringUtils.trimToEmpty(tpl.getContent()), model);
		logger.debug("File Content ==> \r\n" + content);
		
		// 将生成的代码写入文件
		if ("2".equals(genTable.getFlag())){
			
			// 如果选择替换文件，则删除原文件
			if (genTable.getReplaceFile()){
				FileUtils.deleteFile(fileName);
			}
			
			// 创建并写入文件
			if (FileUtils.createFile(fileName)){
				FileUtils.writeToFile(fileName, content, true);
				logger.debug("File Create ==> " + fileName);
				return "生成成功："+fileName+"<br/>";
			}else{
				logger.debug("File Extents ==> " + fileName);
				return "文件已存在："+fileName+"<br/>";
			}
		}
		return fileName+"<br/>";
	}
	
	public static void main(String[] args) {
		try {
			GenConfig config = getConfig();
			System.out.println(config);
			System.out.println(JaxbMapper.toXml(config));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}
